/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.gruposp2p.aularest.model.controller;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import org.gruposp2p.aularest.model.Coursegroup;
import org.gruposp2p.aularest.model.Student;
import org.gruposp2p.aularest.model.Tutor;
import java.util.ArrayList;
import java.util.Collection;
import org.gruposp2p.aularest.model.Score;
import org.gruposp2p.aularest.model.Address;
import org.gruposp2p.aularest.model.Absence;
import org.gruposp2p.aularest.model.controller.exceptions.IllegalOrphanException;
import org.gruposp2p.aularest.model.controller.exceptions.NonexistentEntityException;
import org.gruposp2p.aularest.model.controller.exceptions.PreexistingEntityException;

/**
 *
 * @author jj
 */
public class StudentJpaController {

    public StudentJpaController() {
        emf = Persistence.createEntityManagerFactory("AulaRest_PU");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Student student) throws PreexistingEntityException, Exception {
        if (student.getTutorCollection() == null) {
            student.setTutorCollection(new ArrayList<Tutor>());
        }
        if (student.getScoreCollection() == null) {
            student.setScoreCollection(new ArrayList<Score>());
        }
        if (student.getAddressCollection() == null) {
            student.setAddressCollection(new ArrayList<Address>());
        }
        if (student.getAbsenceCollection() == null) {
            student.setAbsenceCollection(new ArrayList<Absence>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Coursegroup coursegroupId = student.getCoursegroupId();
            if (coursegroupId != null) {
                coursegroupId = em.getReference(coursegroupId.getClass(), coursegroupId.getId());
                student.setCoursegroupId(coursegroupId);
            }
            Collection<Tutor> attachedTutorCollection = new ArrayList<Tutor>();
            for (Tutor tutorCollectionTutorToAttach : student.getTutorCollection()) {
                tutorCollectionTutorToAttach = em.getReference(tutorCollectionTutorToAttach.getClass(), tutorCollectionTutorToAttach.getId());
                attachedTutorCollection.add(tutorCollectionTutorToAttach);
            }
            student.setTutorCollection(attachedTutorCollection);
            Collection<Score> attachedScoreCollection = new ArrayList<Score>();
            for (Score scoreCollectionScoreToAttach : student.getScoreCollection()) {
                scoreCollectionScoreToAttach = em.getReference(scoreCollectionScoreToAttach.getClass(), scoreCollectionScoreToAttach.getId());
                attachedScoreCollection.add(scoreCollectionScoreToAttach);
            }
            student.setScoreCollection(attachedScoreCollection);
            Collection<Address> attachedAddressCollection = new ArrayList<Address>();
            for (Address addressCollectionAddressToAttach : student.getAddressCollection()) {
                addressCollectionAddressToAttach = em.getReference(addressCollectionAddressToAttach.getClass(), addressCollectionAddressToAttach.getId());
                attachedAddressCollection.add(addressCollectionAddressToAttach);
            }
            student.setAddressCollection(attachedAddressCollection);
            Collection<Absence> attachedAbsenceCollection = new ArrayList<Absence>();
            for (Absence absenceCollectionAbsenceToAttach : student.getAbsenceCollection()) {
                absenceCollectionAbsenceToAttach = em.getReference(absenceCollectionAbsenceToAttach.getClass(), absenceCollectionAbsenceToAttach.getId());
                attachedAbsenceCollection.add(absenceCollectionAbsenceToAttach);
            }
            student.setAbsenceCollection(attachedAbsenceCollection);
            em.persist(student);
            if (coursegroupId != null) {
                coursegroupId.getStudentCollection().add(student);
                coursegroupId = em.merge(coursegroupId);
            }
            for (Tutor tutorCollectionTutor : student.getTutorCollection()) {
                tutorCollectionTutor.getStudentCollection().add(student);
                tutorCollectionTutor = em.merge(tutorCollectionTutor);
            }
            for (Score scoreCollectionScore : student.getScoreCollection()) {
                Student oldStudentIdOfScoreCollectionScore = scoreCollectionScore.getStudentId();
                scoreCollectionScore.setStudentId(student);
                scoreCollectionScore = em.merge(scoreCollectionScore);
                if (oldStudentIdOfScoreCollectionScore != null) {
                    oldStudentIdOfScoreCollectionScore.getScoreCollection().remove(scoreCollectionScore);
                    oldStudentIdOfScoreCollectionScore = em.merge(oldStudentIdOfScoreCollectionScore);
                }
            }
            for (Address addressCollectionAddress : student.getAddressCollection()) {
                Student oldStudentIdOfAddressCollectionAddress = addressCollectionAddress.getStudentId();
                addressCollectionAddress.setStudentId(student);
                addressCollectionAddress = em.merge(addressCollectionAddress);
                if (oldStudentIdOfAddressCollectionAddress != null) {
                    oldStudentIdOfAddressCollectionAddress.getAddressCollection().remove(addressCollectionAddress);
                    oldStudentIdOfAddressCollectionAddress = em.merge(oldStudentIdOfAddressCollectionAddress);
                }
            }
            for (Absence absenceCollectionAbsence : student.getAbsenceCollection()) {
                Student oldStudentIdOfAbsenceCollectionAbsence = absenceCollectionAbsence.getStudentId();
                absenceCollectionAbsence.setStudentId(student);
                absenceCollectionAbsence = em.merge(absenceCollectionAbsence);
                if (oldStudentIdOfAbsenceCollectionAbsence != null) {
                    oldStudentIdOfAbsenceCollectionAbsence.getAbsenceCollection().remove(absenceCollectionAbsence);
                    oldStudentIdOfAbsenceCollectionAbsence = em.merge(oldStudentIdOfAbsenceCollectionAbsence);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findStudent(student.getId()) != null) {
                throw new PreexistingEntityException("Student " + student + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Student student) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Student persistentStudent = em.find(Student.class, student.getId());
            Coursegroup coursegroupIdOld = persistentStudent.getCoursegroupId();
            Coursegroup coursegroupIdNew = student.getCoursegroupId();
            Collection<Tutor> tutorCollectionOld = persistentStudent.getTutorCollection();
            Collection<Tutor> tutorCollectionNew = student.getTutorCollection();
            Collection<Score> scoreCollectionOld = persistentStudent.getScoreCollection();
            Collection<Score> scoreCollectionNew = student.getScoreCollection();
            Collection<Address> addressCollectionOld = persistentStudent.getAddressCollection();
            Collection<Address> addressCollectionNew = student.getAddressCollection();
            Collection<Absence> absenceCollectionOld = persistentStudent.getAbsenceCollection();
            Collection<Absence> absenceCollectionNew = student.getAbsenceCollection();
            List<String> illegalOrphanMessages = null;
            for (Score scoreCollectionOldScore : scoreCollectionOld) {
                if (!scoreCollectionNew.contains(scoreCollectionOldScore)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Score " + scoreCollectionOldScore + " since its studentId field is not nullable.");
                }
            }
            for (Absence absenceCollectionOldAbsence : absenceCollectionOld) {
                if (!absenceCollectionNew.contains(absenceCollectionOldAbsence)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Absence " + absenceCollectionOldAbsence + " since its studentId field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (coursegroupIdNew != null) {
                coursegroupIdNew = em.getReference(coursegroupIdNew.getClass(), coursegroupIdNew.getId());
                student.setCoursegroupId(coursegroupIdNew);
            }
            Collection<Tutor> attachedTutorCollectionNew = new ArrayList<Tutor>();
            for (Tutor tutorCollectionNewTutorToAttach : tutorCollectionNew) {
                tutorCollectionNewTutorToAttach = em.getReference(tutorCollectionNewTutorToAttach.getClass(), tutorCollectionNewTutorToAttach.getId());
                attachedTutorCollectionNew.add(tutorCollectionNewTutorToAttach);
            }
            tutorCollectionNew = attachedTutorCollectionNew;
            student.setTutorCollection(tutorCollectionNew);
            Collection<Score> attachedScoreCollectionNew = new ArrayList<Score>();
            for (Score scoreCollectionNewScoreToAttach : scoreCollectionNew) {
                scoreCollectionNewScoreToAttach = em.getReference(scoreCollectionNewScoreToAttach.getClass(), scoreCollectionNewScoreToAttach.getId());
                attachedScoreCollectionNew.add(scoreCollectionNewScoreToAttach);
            }
            scoreCollectionNew = attachedScoreCollectionNew;
            student.setScoreCollection(scoreCollectionNew);
            Collection<Address> attachedAddressCollectionNew = new ArrayList<Address>();
            for (Address addressCollectionNewAddressToAttach : addressCollectionNew) {
                addressCollectionNewAddressToAttach = em.getReference(addressCollectionNewAddressToAttach.getClass(), addressCollectionNewAddressToAttach.getId());
                attachedAddressCollectionNew.add(addressCollectionNewAddressToAttach);
            }
            addressCollectionNew = attachedAddressCollectionNew;
            student.setAddressCollection(addressCollectionNew);
            Collection<Absence> attachedAbsenceCollectionNew = new ArrayList<Absence>();
            for (Absence absenceCollectionNewAbsenceToAttach : absenceCollectionNew) {
                absenceCollectionNewAbsenceToAttach = em.getReference(absenceCollectionNewAbsenceToAttach.getClass(), absenceCollectionNewAbsenceToAttach.getId());
                attachedAbsenceCollectionNew.add(absenceCollectionNewAbsenceToAttach);
            }
            absenceCollectionNew = attachedAbsenceCollectionNew;
            student.setAbsenceCollection(absenceCollectionNew);
            student = em.merge(student);
            if (coursegroupIdOld != null && !coursegroupIdOld.equals(coursegroupIdNew)) {
                coursegroupIdOld.getStudentCollection().remove(student);
                coursegroupIdOld = em.merge(coursegroupIdOld);
            }
            if (coursegroupIdNew != null && !coursegroupIdNew.equals(coursegroupIdOld)) {
                coursegroupIdNew.getStudentCollection().add(student);
                coursegroupIdNew = em.merge(coursegroupIdNew);
            }
            for (Tutor tutorCollectionOldTutor : tutorCollectionOld) {
                if (!tutorCollectionNew.contains(tutorCollectionOldTutor)) {
                    tutorCollectionOldTutor.getStudentCollection().remove(student);
                    tutorCollectionOldTutor = em.merge(tutorCollectionOldTutor);
                }
            }
            for (Tutor tutorCollectionNewTutor : tutorCollectionNew) {
                if (!tutorCollectionOld.contains(tutorCollectionNewTutor)) {
                    tutorCollectionNewTutor.getStudentCollection().add(student);
                    tutorCollectionNewTutor = em.merge(tutorCollectionNewTutor);
                }
            }
            for (Score scoreCollectionNewScore : scoreCollectionNew) {
                if (!scoreCollectionOld.contains(scoreCollectionNewScore)) {
                    Student oldStudentIdOfScoreCollectionNewScore = scoreCollectionNewScore.getStudentId();
                    scoreCollectionNewScore.setStudentId(student);
                    scoreCollectionNewScore = em.merge(scoreCollectionNewScore);
                    if (oldStudentIdOfScoreCollectionNewScore != null && !oldStudentIdOfScoreCollectionNewScore.equals(student)) {
                        oldStudentIdOfScoreCollectionNewScore.getScoreCollection().remove(scoreCollectionNewScore);
                        oldStudentIdOfScoreCollectionNewScore = em.merge(oldStudentIdOfScoreCollectionNewScore);
                    }
                }
            }
            for (Address addressCollectionOldAddress : addressCollectionOld) {
                if (!addressCollectionNew.contains(addressCollectionOldAddress)) {
                    addressCollectionOldAddress.setStudentId(null);
                    addressCollectionOldAddress = em.merge(addressCollectionOldAddress);
                }
            }
            for (Address addressCollectionNewAddress : addressCollectionNew) {
                if (!addressCollectionOld.contains(addressCollectionNewAddress)) {
                    Student oldStudentIdOfAddressCollectionNewAddress = addressCollectionNewAddress.getStudentId();
                    addressCollectionNewAddress.setStudentId(student);
                    addressCollectionNewAddress = em.merge(addressCollectionNewAddress);
                    if (oldStudentIdOfAddressCollectionNewAddress != null && !oldStudentIdOfAddressCollectionNewAddress.equals(student)) {
                        oldStudentIdOfAddressCollectionNewAddress.getAddressCollection().remove(addressCollectionNewAddress);
                        oldStudentIdOfAddressCollectionNewAddress = em.merge(oldStudentIdOfAddressCollectionNewAddress);
                    }
                }
            }
            for (Absence absenceCollectionNewAbsence : absenceCollectionNew) {
                if (!absenceCollectionOld.contains(absenceCollectionNewAbsence)) {
                    Student oldStudentIdOfAbsenceCollectionNewAbsence = absenceCollectionNewAbsence.getStudentId();
                    absenceCollectionNewAbsence.setStudentId(student);
                    absenceCollectionNewAbsence = em.merge(absenceCollectionNewAbsence);
                    if (oldStudentIdOfAbsenceCollectionNewAbsence != null && !oldStudentIdOfAbsenceCollectionNewAbsence.equals(student)) {
                        oldStudentIdOfAbsenceCollectionNewAbsence.getAbsenceCollection().remove(absenceCollectionNewAbsence);
                        oldStudentIdOfAbsenceCollectionNewAbsence = em.merge(oldStudentIdOfAbsenceCollectionNewAbsence);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = student.getId();
                if (findStudent(id) == null) {
                    throw new NonexistentEntityException("The student with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Student student;
            try {
                student = em.getReference(Student.class, id);
                student.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The student with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            Collection<Score> scoreCollectionOrphanCheck = student.getScoreCollection();
            for (Score scoreCollectionOrphanCheckScore : scoreCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Student (" + student + ") cannot be destroyed since the Score " + scoreCollectionOrphanCheckScore + " in its scoreCollection field has a non-nullable studentId field.");
            }
            Collection<Absence> absenceCollectionOrphanCheck = student.getAbsenceCollection();
            for (Absence absenceCollectionOrphanCheckAbsence : absenceCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Student (" + student + ") cannot be destroyed since the Absence " + absenceCollectionOrphanCheckAbsence + " in its absenceCollection field has a non-nullable studentId field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Coursegroup coursegroupId = student.getCoursegroupId();
            if (coursegroupId != null) {
                coursegroupId.getStudentCollection().remove(student);
                coursegroupId = em.merge(coursegroupId);
            }
            Collection<Tutor> tutorCollection = student.getTutorCollection();
            for (Tutor tutorCollectionTutor : tutorCollection) {
                tutorCollectionTutor.getStudentCollection().remove(student);
                tutorCollectionTutor = em.merge(tutorCollectionTutor);
            }
            Collection<Address> addressCollection = student.getAddressCollection();
            for (Address addressCollectionAddress : addressCollection) {
                addressCollectionAddress.setStudentId(null);
                addressCollectionAddress = em.merge(addressCollectionAddress);
            }
            em.remove(student);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Student> findStudentEntities() {
        return findStudentEntities(true, -1, -1);
    }

    public List<Student> findStudentEntities(int maxResults, int firstResult) {
        return findStudentEntities(false, maxResults, firstResult);
    }

    private List<Student> findStudentEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Student as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Student findStudent(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Student.class, id);
        } finally {
            em.close();
        }
    }

    public int getStudentCount() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Student as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
